package mqtt

import helpers.Configuration
import org.fusesource.mqtt.client._

import scala.util.Random

/**
 * @author XiaoBin on 2019-04-11.
 */
class MQTTContext(configuration: Configuration, prefix: String = "mqtt") {

  // Controlling MQTT Options
  private def host: String                = configuration.getOptional[String](appendable("host")).getOrElse("tcp://localhost:1883")
  private def clientID: Option[String]    = configuration.getOptional[String](appendable("clientId"))
  private def cleanSession: Boolean       = configuration.getOptional[Boolean](appendable("cleanSession")).getOrElse(true)
  private def keepAlive: Int              = configuration.getOptional[Int](appendable("keepAlive")).getOrElse(1000)
  private def username: String            = configuration.getOptional[String](appendable("username")).getOrElse("Emqx")
  private def password: String            = configuration.getOptional[String](appendable("password")).getOrElse("Emqx2019*#!")
  private def willTopic: Option[String]   = configuration.getOptional[String](appendable("willTopic"))
  private def willQos: Option[String]     = configuration.getOptional[String](appendable("willQos"))
  private def willRetain: Option[Boolean] = configuration.getOptional[Boolean](appendable("willRetain"))
  private def version: String             = configuration.getOptional[String](appendable("version")).getOrElse("3.1")

  // Controlling Connection Reconnects
  private def connectAttemptsMax: Option[Int]   = configuration.getOptional[Int](appendable("connectAttemptsMax"))
  private def reconnectAttemptsMax: Option[Int] = configuration.getOptional[Int](appendable("reconnectAttemptsMax"))
  private def reconnectDelay: Option[Int]       = configuration.getOptional[Int](appendable("reconnectDelay"))
  private def reconnectDelayMax: Option[Int]    = configuration.getOptional[Int](appendable("reconnectDelayMax"))
  private def setReconnectBackOffMultiplier: Option[Int] =
    configuration.getOptional[Int](appendable("setReconnectBackOffMultiplier"))

  // Configuring Socket Options
  private def receiveBufferSize: Option[Int] = configuration.getOptional[Int](appendable("receiveBufferSize"))
  private def sendBufferSize: Option[Int]    = configuration.getOptional[Int](appendable("sendBufferSize"))
  private def trafficClass: Option[Int]      = configuration.getOptional[Int](appendable("trafficClass"))

  //  Using SSL connections
  //  If you want to connect over SSL/TLS instead of TCP, use an "ssl://" or "tls://" URI prefix instead of "tcp://" for the host field. For finer grained control of which algorithm is used. Supported protocol values are:
  //
  //  ssl:// - Use the JVM default version of the SSL algorithm.
  //  sslv*:// - Use a specific SSL version where * is a version supported by your JVM. Example: sslv3
  //  tls:// - Use the JVM default version of the TLS algorithm.
  //  tlsv*:// - Use a specific TLS version where * is a version supported by your JVM. Example: tlsv1.1

  // Throttling Connections
  private def maxReadRate: Option[Int]  = configuration.getOptional[Int](appendable("maxReadRate"))
  private def maxWriteRate: Option[Int] = configuration.getOptional[Int](appendable("maxWriteRate"))

  // Selecting the Dispatch Queue
  private def dispatchQueue: Option[Int] = configuration.getOptional[Int](appendable("dispatchQueue"))

  private lazy val mqttClient: MQTT = new MQTT()
  mqttClient.setHost(host)
  mqttClient.setClientId(clientID.getOrElse(Random.alphanumeric.take(23).mkString))
  mqttClient.setCleanSession(cleanSession)
  mqttClient.setKeepAlive(keepAlive.toShort)
  mqttClient.setUserName(username)
  mqttClient.setPassword(password)
  willTopic.foreach(mqttClient.setWillTopic)
  willQos.foreach(name ⇒ mqttClient.setWillQos(QoS.valueOf(name)))
  willRetain.foreach(mqttClient.setWillRetain)
  mqttClient.setVersion(version)

  def futureConnection: FutureConnection     = mqttClient.futureConnection()
  def blockingConnection: BlockingConnection = mqttClient.blockingConnection()
  def callbackConnection: CallbackConnection = mqttClient.callbackConnection()

  protected def appendable(part: String): String = if (prefix.isEmpty) part else s"$prefix.$part"
}

//object MQTTContext {
//
//  protected def appendable(prefix: String, part: String): String = if (prefix.isEmpty) part else s"$prefix.$part"
//
//  case class ControllingOptionConfig(
//      host: String,
//      clientID: String,
//      cleanSession: Boolean,
//      keepAlive: Int,
//      username: String,
//      password: String,
//      willTopic: Option[String],
//      willQos: Option[String],
//      willRetain: Option[Boolean],
//      version: String
//  )
//
//  object ControllingOptionConfig {
//
//    def fromConfiguration(configuration: Configuration, prefix: String): ControllingOptionConfig =
//      new ControllingOptionConfig(
//        host = configuration.getOptional[String](appendable(prefix, "host")).getOrElse("tcp://localhost:1883"),
//        clientID =
//          configuration.getOptional(appendable(prefix, "clientId")).getOrElse(Random.alphanumeric.take(23).mkString),
//        cleanSession = configuration.getOptional[Boolean](appendable(prefix, "cleanSession")).getOrElse(true),
//        keepAlive = configuration.getEssentialInt(appendable(prefix, "keepAlive")),
//        username = configuration.getOptional[String](appendable(prefix, "username")).getOrElse("Emqx"),
//        password = configuration.getOptional[String](appendable(prefix, "password")).getOrElse("Emqx2019*#!"),
//        willTopic = configuration.getOptional[String](appendable(prefix, "willTopic")),
//        willQos = configuration.getOptional[String](appendable(prefix, "willQos")),
//        willRetain = configuration.getOptional[Boolean](appendable(prefix, "willRetain")),
//        version = configuration.getEssentialString(appendable(prefix, "version"))
//      )
//  }
//}
